/* Copyright (c) 2015,2016 Lucky Byte, Inc.
 */
package com.lucky_byte.pay.jar;

import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 加解密函数，采用 BouncyCastleProvider(bcprov.jar)
 */
public class Crypto
{
	private static final Logger logger = LogManager.getLogger();

	// 动态加载 bcprov 加解密包
	static {
		Security.addProvider(
				new org.bouncycastle.jce.provider.BouncyCastleProvider());
	}

	/**
	 * 去加密块 size
	 *
	 * @param transformation
	 */
	public static int blockSize(String transformation) {
		try {
			Cipher cipher = Cipher.getInstance(transformation, "BC");
			return cipher.getBlockSize();
		} catch (Exception e) {
			logger.error("取加密块大小错误[{}][{}].", e.getMessage(),
					e.getClass().getSimpleName());
			return -1;
		}
	}

	/**
	 * 块加密
	 *
	 * @param algor 加密算法，例如 DES, AES ...
	 * @param mode 加密模式，例如 ECB, ...
	 * @param padding 填充方式，例如 NoPadding, ...
	 * @param key 密钥
	 * @param clear_text 明文数据
	 * @param text_size 明文数据长度
	 *
	 * @return 加密后密文
	 */
	private static byte[] encrypt(String algor, String mode, String padding,
			Key key, byte[] clear_text, int clear_size) {
		if (algor == null || padding == null || key == null ||
				clear_text == null) {
			logger.error("加密参数输入错误，请检查.");
			return null;
		}
		if (clear_size <= 0) {
			clear_size = clear_text.length;
		}
		try {
			String transformation = algor + "/" + mode + "/" + padding;
			Cipher cipher = Cipher.getInstance(transformation, "BC");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			int cipher_size = cipher.getOutputSize(clear_size);
			byte[] cipher_text = new byte[cipher_size];
			int n = cipher.update(clear_text, 0, clear_size, cipher_text, 0);
			n += cipher.doFinal(cipher_text, n);
			return cipher_text;
		} catch (Exception e) {
			logger.error("采用[{}/{}/{}]方式加密失败[{}].",
					algor, mode, padding, e.getMessage(),
					e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * 块加密，采用 EBC 模式
	 *
	 * @param algor 加密算法，例如 DES, AES ...
	 * @param padding 填充方式，例如 NoPadding, ...
	 * @param key 密钥
	 * @param clear_text 明文数据
	 * @param text_size 明文数据长度
	 *
	 * @return 加密后密文
	 */
	private static byte[] encrypt(String algor, String padding,
			Key key, byte[] clear_text, int clear_size) {
		return encrypt(algor, "ECB", padding, key, clear_text, clear_size);
	}

	/**
	 * 对称块解密
	 *
	 * @param algor 加密算法，例如 DES, AES ...
	 * @param mode 加密模式，例如 ECB, ...
	 * @param padding 填充方式，例如 NoPadding, ...
	 * @param key 密钥
	 * @param cipher_text 密文数据
	 * @param cipher_size 密文数据长度
	 *
	 * @return 解密后明文
	 */
	private static byte[] decrypt(String algor, String mode, String padding,
			Key key, byte[] cipher_text, int cipher_size) {
		if (algor == null || padding == null || key == null ||
				cipher_text == null) {
			logger.error("解密参数输入错误，请检查.");
			return null;
		}
		if (cipher_size <= 0) {
			cipher_size = cipher_text.length;
		}
		try {
			String transformation = algor + "/" + mode + "/" + padding;
			Cipher cipher = Cipher.getInstance(transformation, "BC");
			cipher.init(Cipher.DECRYPT_MODE, key);
			int clear_size = cipher.getOutputSize(cipher_size);
			byte[] clear_text = new byte[clear_size];
			int n = cipher.update(cipher_text, 0, cipher_size, clear_text, 0);
			n += cipher.doFinal(clear_text, n);
			// 解密后数据去除填充字符
			if (n != clear_size) {
				byte[] ret = new byte[n];
				System.arraycopy(clear_text, 0, ret, 0, n);
				return ret;
			}
			return clear_text;
		} catch (Exception e) {
			logger.error("采用[{}/{}/{}]方式解密失败[{}][{}].",
					algor, mode, padding, e.getMessage(),
					e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * 对称块解密，采用 ECB 模式
	 *
	 * @param algor 加密算法，例如 DES, AES ...
	 * @param padding 填充方式，例如 NoPadding, ...
	 * @param key 密钥
	 * @param cipher_text 密文数据
	 * @param cipher_size 密文数据长度
	 *
	 * @return 解密后明文
	 */
	private static byte[] decrypt(String algor, String padding,
			SecretKey key, byte[] cipher_text, int cipher_size) {
		return decrypt(algor, "ECB", padding, key, cipher_text, cipher_size);
	}

	/**
	 * DES 对称块加密，采用 ECB 模式
	 *
	 * @param key 加密密钥
	 * @param clear_text 明文数据
	 * @param clear_size 明文数据长度
	 * @return 加密后密文
	 */
	private static byte[] DESEncrypt(String padding, byte[] key,
			byte[] clear_text, int clear_size) {
		try {
			DESKeySpec key_spec = new DESKeySpec(key);
			SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
			SecretKey secret_key = factory.generateSecret(key_spec);
			return encrypt("DES", padding, secret_key,
					clear_text, clear_size);
		} catch (Exception e) {
			logger.error("DES 加密错误[{}][{}].", e.getMessage(),
					e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * DES 对称块解密，采用 ECB 模式
	 *
	 * @param key 解密密钥
	 * @param cipher_text 密文数据
	 * @param cipher_size 密文数据长度
	 * @return 解密后明文
	 */
	private static byte[] DESDecrypt(String padding, byte[] key,
			byte[] cipher_text, int cipher_size) {
		try {
			DESKeySpec key_spec = new DESKeySpec(key);
			SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
			SecretKey secret_key = factory.generateSecret(key_spec);
			return decrypt("DES", padding, secret_key,
					cipher_text, cipher_size);
		} catch (Exception e) {
			logger.error("DES 解密错误[{}][{}].", e.getMessage(),
					e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * DES 对称块加密，采用 ECB 模式，NoPadding 填充
	 *
	 * @param key 加密密钥
	 * @param clear_text 明文数据
	 * @param clear_size 明文数据长度
	 * @return 加密后密文
	 */
	public static byte[] DESEncrypt(byte[] key, byte[] clear_text,
			int clear_size) {
		if (clear_text == null) {
			logger.error("DES 加密参数错误.");
			return null;
		}
		if (clear_size <= 0) {
			clear_size = clear_text.length;
		}
		if (clear_size % 8 != 0) {
			logger.error("DES NoPadding 模式下，明文长度[{}]不是8字节的整倍数.",
					clear_size);
			return null;
		}
		return DESEncrypt("NoPadding", key, clear_text, clear_size);
	}

	/**
	 * DES 对称块解密，采用 ECB 模式，NoPadding 填充
	 *
	 * @param key 解密密钥
	 * @param cipher_text 密文数据
	 * @param cipher_size 密文数据长度
	 * @return 解密后明文
	 */
	public static byte[] DESDecrypt(byte[] key, byte[] cipher_text,
			int cipher_size) {
		if (cipher_text == null) {
			logger.error("DES 解密参数错误.");
			return null;
		}
		if (cipher_size <= 0) {
			cipher_size = cipher_text.length;
		}
		if (cipher_size % 8 != 0) {
			logger.error("DES NoPadding 模式下，密文长度[{}]不是8字节的整倍数.",
					cipher_size);
			return null;
		}
		return DESDecrypt("NoPadding", key, cipher_text, cipher_size);
	}

	/**
	 * DES 对称块加密，采用 ECB 模式，PKCS7Padding 填充
	 *
	 * @param key 加密密钥
	 * @param clear_text 明文数据
	 * @param clear_size 明文数据长度
	 * @return 密文
	 */
	public static byte[] DESEncryptPadding(byte[] key,
			byte[] clear_text, int clear_size) {
		return DESEncrypt("PKCS7Padding", key, clear_text, clear_size);
	}

	/**
	 * DES 对称块解密，采用 ECB 模式，PKCS7Padding 填充
	 *
	 * @param key 解密密钥
	 * @param cipher_text 密文数据
	 * @param cipher_size 密文数据长度
	 * @return 解密后明文
	 */
	public static byte[] DESDecryptPadding(byte[] key,
			byte[] cipher_text, int cipher_size) {
		return DESDecrypt("PKCS7Padding", key, cipher_text, cipher_size);
	}

	/**
	 * 变长密钥 DES 加密，如果密钥长度为 8，采用 DES 加密，如果长度为 16 或 32，
	 * 则采用 DESede 加密
	 *
	 * @param key 密钥
	 * @param clear_text 待加密数据
	 * @param clear_size 待加密数据长度
	 * @return 加密后数据
	 */
	public static byte[] DESEncryptEDE(byte[] key, byte[] clear_text,
			int clear_size) {
		byte[] key1, key2, key3;
		switch (key.length) {
		case 8:
			return DESEncrypt(key, clear_text, clear_size);
		case 16:
			key1 = new byte[8];
			key2 = new byte[8];
			System.arraycopy(key, 0, key1, 0, 8);
			System.arraycopy(key, 8, key2, 0, 8);
			key3 = key1;
			break;
		case 32:
			key1 = new byte[8];
			key2 = new byte[8];
			key3 = new byte[8];
			System.arraycopy(key, 0,  key1, 0, 8);
			System.arraycopy(key, 8,  key2, 0, 8);
			System.arraycopy(key, 16, key3, 0, 8);
			break;
		default:
			logger.error("DES密钥长度[{}]无效.", key.length);
			return null;
		}
		return Crypto.DESEncrypt(key1, Crypto.DESDecrypt(key2,
				Crypto.DESEncrypt(key3, clear_text, clear_size), 0), 0);
	}

	/**
	 * 变长密钥 DES 解密，如果密钥长度为 8，采用 DES 加密，如果长度为 16 或 32，
	 * 则采用 DESede 解密
	 *
	 * @param key 密钥
	 * @param cipher_text 待解密数据
	 * @param cipher_size 待解密数据长度
	 * @return 解密后数据
	 */
	public static byte[] DESDecryptDED(byte[] key, byte[] cipher_text,
			int cipher_size) {
		byte[] key1, key2, key3;
		switch (key.length) {
		case 8:
			return DESEncrypt(key, cipher_text, cipher_size);
		case 16:
			key1 = new byte[8];
			key2 = new byte[8];
			System.arraycopy(key, 0, key1, 0, 8);
			System.arraycopy(key, 8, key2, 0, 8);
			key3 = key1;
			break;
		case 32:
			key1 = new byte[8];
			key2 = new byte[8];
			key3 = new byte[8];
			System.arraycopy(key, 0,  key1, 0, 8);
			System.arraycopy(key, 8,  key2, 0, 8);
			System.arraycopy(key, 16, key3, 0, 8);
			break;
		default:
			logger.error("DES密钥长度[{}]无效.", key.length);
			return null;
		}
		return Crypto.DESDecrypt(key1, Crypto.DESEncrypt(key2,
				Crypto.DESDecrypt(key3, cipher_text, cipher_size), 0), 0);
	}

	/**
	 * 通过 algor 算法计算摘要
	 *
	 * @param input 输入数据
	 * @param offset 输入数据起始偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 data.length
	 * @param algor 摘要算法，例如 'SHA-1' 等等
	 * @return 摘要代码
	 */
	private static byte[] digest(byte[] input, int offset,
			int length, String algor) {
		if (input == null) {
			logger.error("计算[{}]摘要的输入数据不能为空.", algor);
			return null;
		}
		if (length <= 0) {
			length = input.length;
		}
		try {
			MessageDigest md = MessageDigest.getInstance(algor, "BC");
			md.update(input, offset, length);
			return md.digest();
		} catch (Exception e) {
			logger.error("计算[{}]摘要错误[{}][{}].", algor,
					e.getMessage(), e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * 计算 SHA1 摘要码
	 *
	 * @param input 输入数据
	 * @param offset 输入数据起始偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 data.length
	 * @return 摘要代码
	 */
	public static byte[] sha1(byte[] input, int offset, int length) {
		return digest(input, offset, length, "SHA-1");
	}

	/**
	 * 计算 SHA1 摘要码
	 *
	 * @param input 输入数据
	 * @return 摘要代码
	 */
	public static byte[] sha1(byte[] input) {
		return sha1(input, 0, 0);
	}

	/**
	 * 通过私钥进行签名
	 *
	 * @param private_key 私钥
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0,  表示取 input.length
	 * @param algor 签名算法，例如 'SHA1withRSA'
	 * @return
	 */
	private static byte[] sign(PrivateKey private_key, byte[] input,
			int offset, int length, String algor) {
		if (input == null) {
			logger.error("计算[{}]数字签名的输入数据不能为空.", algor);
			return null;
		}
		if (length <= 0) {
			length = input.length;
		}
		try {
			Signature signature = Signature.getInstance(algor, "BC");
			signature.initSign(private_key);
			signature.update(input, offset, length);
			return signature.sign();
		} catch (Exception e) {
			logger.error("计算[{}]数字签名错误[{}][{}].", algor,
					e.getMessage(), e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * 通过公钥进行签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0, 表示取 input.length
	 * @param to_verify 待验证数据
	 * @param algor 签名算法，例如 'SHA1withRSA'
	 * @return 签名是否通过
	 */
	private static boolean verify(PublicKey public_key, byte[] input,
			int offset, int length, byte[] to_verify, String algor) {
		if (input == null) {
			logger.error("验证[{}]数字签名的输入数据不能为空.", algor);
			return false;
		}
		if (length <= 0) {
			length = input.length;
		}
		try {
			Signature signature = Signature.getInstance(algor, "BC");
			signature.initVerify(public_key);
			signature.update(input, offset, length);
			return signature.verify(to_verify);
		} catch (Exception e) {
			logger.error("验证[{}]数字签名错误[{}].", algor, e.getMessage(),
					e.getClass().getSimpleName());
			return false;
		}
	}

	/**
	 * 通过证书进行签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0, 表示取 input.length
	 * @param to_verify 待验证数据
	 * @param algor 签名算法，例如 'SHA1withRSA'
	 * @return 签名是否通过
	 */
	private static boolean verify(Certificate certificate, byte[] input,
			int offset, int length, byte[] to_verify, String algor) {
		if (input == null) {
			logger.error("验证[{}]数字签名的输入数据不能为空.", algor);
			return false;
		}
		if (length <= 0) {
			length = input.length;
		}
		try {
			Signature signature = Signature.getInstance(algor, "BC");
			signature.initVerify(certificate);
			signature.update(input, offset, length);
			return signature.verify(to_verify);
		} catch (Exception e) {
			logger.error("验证[{}]数字签名错误[{}][{}].", algor,
					e.getMessage(), e.getClass().getSimpleName());
			return false;
		}
	}

	/**
	 * 计算 DSA 数字签名
	 *
	 * @param private_key 私钥，必须是符合 DSA 规范的密钥
	 * @param input 签名数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度
	 * @return 签名
	 */
	public static byte[] signDSA(PrivateKey private_key, byte[] input,
			int offset, int length) {
		return sign(private_key, input, offset, length, "DSA");
	}

	/**
	 * 计算 DSA 数字签名
	 *
	 * @param private_key 私钥，必须是符合 DSA 规范的密钥
	 * @param input 签名数据
	 * @return 签名
	 */
	public static byte[] signDSA(PrivateKey private_key, byte[] input) {
		return signDSA(private_key, input, 0, 0);
	}

	/**
	 * 通过 DSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyDSA(PublicKey public_key, byte[] input,
			int offset, int length, byte[] to_verify) {
		return verify(public_key, input, offset, length, to_verify, "DSA");
	}

	/**
	 * 通过 DSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyDSA(PublicKey public_key, byte[] input,
			byte[] to_verify) {
		return verifyDSA(public_key, input, 0, 0, to_verify);
	}

	/**
	 * 通过 DSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyDSA(Certificate certificate, byte[] input,
			int offset, int length, byte[] to_verify) {
		return verify(certificate, input, offset, length, to_verify, "DSA");
	}

	/**
	 * 通过 DSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public boolean verifyDSA(Certificate certificate, byte[] input,
			byte[] to_verify) {
		return verifyDSA(certificate, input, 0, 0, to_verify);
	}

	/**
	 * 计算 Elliptic Curve DSA 数字签名
	 *
	 * @param private_key 私钥，必须是符合 ECDSA 规范的密钥
	 * @param input 签名数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度
	 * @return 签名
	 */
	public static byte[] signECDSA(PrivateKey private_key, byte[] input,
			int offset, int length) {
		return sign(private_key, input, offset, length, "ECDSA");
	}

	/**
	 * 计算 Elliptic Curve DSA 数字签名
	 *
	 * @param private_key 私钥，必须是符合 ECDSA 规范的密钥
	 * @param input 签名数据
	 * @return 签名
	 */
	public static byte[] signECDSA(PrivateKey private_key, byte[] input) {
		return signECDSA(private_key, input, 0, 0);
	}

	/**
	 * 通过 Elliptic Curve DSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyECDSA(PublicKey public_key, byte[] input,
			int offset, int length, byte[] to_verify) {
		return verify(public_key, input, offset, length, to_verify, "ECDSA");
	}

	/**
	 * 通过 Elliptic Curve DSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyECDSA(PublicKey public_key, byte[] input,
			byte[] to_verify) {
		return verifyECDSA(public_key, input, 0, 0, to_verify);
	}

	/**
	 * 通过 Elliptic Curve DSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyECDSA(Certificate certificate, byte[] input,
			int offset, int length, byte[] to_verify) {
		return verify(certificate, input, offset, length, to_verify, "ECDSA");
	}

	/**
	 * 通过 Elliptic Curve DSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifyECDSA(Certificate certificate,
			byte[] input, byte[] to_verify) {
		return verifyECDSA(certificate, input, 0, 0, to_verify);
	}

	/**
	 * 计算 SHA1withRSA 数字签名
	 *
	 * @param private_key 私钥
	 * @param input 签名数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度
	 * @return 签名
	 */
	public static byte[] signSHA1WithRSA(PrivateKey private_key,
			byte[] input, int offset, int length) {
		return sign(private_key, input, offset, length, "SHA1withRSA");
	}

	/**
	 * 计算 SHA1withRSA 数字签名
	 *
	 * @param private_key 私钥
	 * @param input 签名数据
	 * @return 签名
	 */
	public static byte[] signSHA1WithRSA(PrivateKey private_key, byte[] input) {
		return signSHA1WithRSA(private_key, input, 0, 0);
	}

	/**
	 * 通过 SHA1withRSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifySHA1WithRSA(PublicKey public_key,
			byte[] input, int offset, int length, byte[] to_verify) {
		return verify(public_key, input, offset, length, to_verify,
				"SHA1withRSA");
	}

	/**
	 * 通过 SHA1withRSA 验证数字签名
	 *
	 * @param public_key 公钥
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifySHA1WithRSA(PublicKey public_key,
			byte[] input, byte[] to_verify) {
		return verifySHA1WithRSA(public_key, input, 0, 0, to_verify);
	}

	/**
	 * 通过 SHA1withRSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param offset 输入数据偏移
	 * @param length 输入数据长度，小于或等于 0 表示取 input.length
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifySHA1WithRSA(Certificate certificate,
			byte[] input, int offset, int length, byte[] to_verify) {
		return verify(certificate, input, offset, length, to_verify,
				"SHA1withRSA");
	}

	/**
	 * 通过 SHA1withRSA 验证数字签名
	 *
	 * @param certificate 公钥证书
	 * @param input 签名输入数据
	 * @param to_verify 待验证数据
	 * @return 签名是否通过
	 */
	public static boolean verifySHA1withRSA(Certificate certificate,
			byte[] input, byte[] to_verify) {
		return verifySHA1WithRSA(certificate, input, 0, 0, to_verify);
	}

	/**
	 * 检查证书有效期，这里只是给出警告信息, 严格来讲，过期的证书是不允许使用的
	 */
	private static boolean checkCertificate(X509Certificate x509_cert,
			File cert_file, String old_alias) {
		logger.trace("读取X.509证书[{}]信息：\n原别名: [{}]\n序号: [{}]\n"
				+ "起始日期: [{}]\n结束日期: [{}]\n所有者: [{}]\n发行机构: [{}]",
				cert_file.getName(), old_alias != null ? old_alias : "",
				x509_cert.getSerialNumber(), x509_cert.getNotBefore(),
				x509_cert.getNotAfter(), x509_cert.getIssuerX500Principal(),
				x509_cert.getIssuerDN());
		try {
			x509_cert.checkValidity();
		} catch (CertificateExpiredException e) {
			logger.warn("证书[{}]已于[{}]过期，请联系更换!",
					cert_file.getName(), 
					new SimpleDateFormat("yyyy年MM月dd日").format(
							x509_cert.getNotAfter()));
		} catch (CertificateNotYetValidException e) {
			logger.warn("证书[{}]至[{}]方生效，请联系更换!",
					cert_file.getName(),
					new SimpleDateFormat("yyyy年MM月dd日").format(
							x509_cert.getNotBefore()));
		}
		return true;
	}

	/**
	 * 读取 X.509 证书
	 *
	 * @param x509_file 证书输入流
	 * @return X509Certificate or null
	 * @throws Exception 异常
	 */
	public static X509Certificate readX509Certificate(File x509_file)
			throws Exception {
		CertificateFactory factory =
				CertificateFactory.getInstance("X.509", "BC");
		X509Certificate x509_cert =
				(X509Certificate) factory.generateCertificate(
						new FileInputStream(x509_file));
		if (!checkCertificate(x509_cert, x509_file, null)) {
			return null;
		}
		return x509_cert;
	}

	/**
	 * 从私钥证书文件中读取私钥
	 *
	 * @param key_file 私钥证书文件
	 * @param format 格式, PKCS12, JKS, JCEKS
	 * @param passwd 文件保护密码
	 * @return 私钥
	 */
	public static PrivateKeyEntry readPrivateKeyEntry(File key_file,
			String format, String passwd) {
		try {
			// 打开证书文件
			KeyStore store = KeyStore.getInstance(format);
			if (passwd != null) {
				store.load(new FileInputStream(key_file), passwd.toCharArray());
			} else {
				store.load(new FileInputStream(key_file), null);
			}
			// 获取别名列表
			Enumeration<?> enumer = store.aliases();
			if (!enumer.hasMoreElements()) {
				logger.error("[{}]中记录为空，请检查.", key_file.getName());
				return null;
			}
			// 取第一项，后续的忽略
			String old_alias = (String) enumer.nextElement();
			PasswordProtection prot_param = null;
			if (passwd != null) {
				prot_param = new PasswordProtection(passwd.toCharArray());
			}
			Entry entry = store.getEntry(old_alias, prot_param);
			if (!(entry instanceof PrivateKeyEntry)) {
				logger.warn("[{}]中存储的不是私钥而是[{}]，请检查.",
						key_file.getName(), entry.getClass().getSimpleName());
			}
			PrivateKeyEntry key_entry = (PrivateKeyEntry) entry;
			if (!checkCertificate((X509Certificate) key_entry.getCertificate(),
					key_file, old_alias)) {
				return null;
			}
			return key_entry;
		} catch (Exception e) {
			logger.error("从[{}]中读取私钥错误[{}][{}].", key_file.getName(),
					e.getMessage(), e.getClass().getSimpleName());
			return null;
		}
	}

	/**
	 * RSA 公钥加密
	 */
	public byte[] RSAEncrypt(String padding, String mode,
			PublicKey public_key, byte[] input, int input_size) {
		return encrypt("RSA", mode, padding, public_key, input, input_size);
	}

	/**
	 * RSA 公钥加密，采用 ECB
	 */
	public byte[] RSAEncrypt(String padding,
			PublicKey public_key, byte[] input, int input_size) {
		return encrypt("RSA", "ECB", padding, public_key, input, input_size);
	}

	/**
	 * RSA 公钥加密，采用 ECB/PKCS1Padding
	 */
	public byte[] RSAEncrypt(PublicKey public_key,
			byte[] input, int input_size) {
		return encrypt("RSA", "ECB", "PKCS1Padding",
				public_key, input, input_size);
	}

	/**
	 * RSA 公钥加密
	 */
	public byte[] RSAEncrypt(String padding, String mode,
			X509Certificate cert, byte[] input, int input_size) {
		return encrypt("RSA", mode, padding,
				cert.getPublicKey(), input, input_size);
	}

	/**
	 * RSA 公钥加密
	 */
	public byte[] RSAEncrypt(String padding,
			X509Certificate cert, byte[] input, int input_size) {
		return encrypt("RSA", "ECB", padding,
				cert.getPublicKey(), input, input_size);
	}

	/**
	 * RSA 公钥加密
	 */
	public byte[] RSAEncrypt(X509Certificate cert,
			byte[] input, int input_size) {
		return encrypt("RSA", "ECB", "PKCS1Padding",
				cert.getPublicKey(), input, input_size);
	}

}
